Eine detaillierte Untersuchung von Cross-Origin Resource Sharing (CORS) und Preflight-Anfragen. Erfahren Sie, wie Sie CORS-Probleme behandeln und Ihre Webanwendungen für ein globales Publikum sichern.
CORS entmystifiziert: Eine tiefgehende Analyse der JavaScript Preflight-Request-Handhabung
In der ständig wachsenden Welt der Webentwicklung ist Sicherheit von größter Bedeutung. Cross-Origin Resource Sharing (CORS) ist ein entscheidender Sicherheitsmechanismus, der von Webbrowsern implementiert wird, um Webseiten daran zu hindern, Anfragen an eine andere Domäne als diejenige zu stellen, von der die Webseite bereitgestellt wurde. Dies ist eine grundlegende Sicherheitsfunktion, die entwickelt wurde, um zu verhindern, dass bösartige Websites auf sensible Daten zugreifen. Dieser umfassende Leitfaden wird sich mit den Feinheiten von CORS befassen und sich speziell auf die Handhabung von Preflight-Anfragen konzentrieren. Wir werden das „Warum“, „Was“ und „Wie“ von CORS untersuchen und praktische Beispiele sowie Lösungen für häufige Probleme liefern, auf die Entwickler weltweit stoßen.
Verständnis der Same-Origin Policy
Im Herzen von CORS liegt die Same-Origin Policy (SOP). Diese Richtlinie ist ein Sicherheitsmechanismus auf Browserebene, der Skripte, die von einer Herkunft ausgeführt werden, daran hindert, auf Ressourcen von einer anderen Herkunft zuzugreifen. Eine Herkunft wird durch das Protokoll (z. B. HTTP oder HTTPS), die Domäne (z. B. example.com) und den Port (z. B. 80 oder 443) definiert. Zwei URLs haben dieselbe Herkunft, wenn diese drei Komponenten exakt übereinstimmen.
Zum Beispiel:
https://www.example.com/app1/index.htmlundhttps://www.example.com/app2/index.htmlhaben dieselbe Herkunft (gleiches Protokoll, gleiche Domäne und gleicher Port).https://www.example.com/index.htmlundhttp://www.example.com/index.htmlhaben unterschiedliche Herkünfte (unterschiedliche Protokolle).https://www.example.com/index.htmlundhttps://api.example.com/index.htmlhaben unterschiedliche Herkünfte (unterschiedliche Subdomains gelten als unterschiedliche Domänen).https://www.example.com:8080/index.htmlundhttps://www.example.com/index.htmlhaben unterschiedliche Herkünfte (unterschiedliche Ports).
Die SOP soll verhindern, dass bösartige Skripte auf einer Website auf sensible Daten wie Cookies oder Benutzerauthentifizierungsinformationen auf einer anderen Website zugreifen. Obwohl sie für die Sicherheit unerlässlich ist, kann die SOP auch einschränkend sein, insbesondere wenn legitime Cross-Origin-Anfragen erforderlich sind.
Was ist Cross-Origin Resource Sharing (CORS)?
CORS ist ein Mechanismus, der es Servern ermöglicht, anzugeben, welche Herkünfte (Domänen, Schemata oder Ports) auf ihre Ressourcen zugreifen dürfen. Es lockert im Wesentlichen die SOP und ermöglicht einen kontrollierten Cross-Origin-Zugriff. CORS wird mithilfe von HTTP-Headern implementiert, die zwischen dem Client (typischerweise ein Webbrowser) und dem Server ausgetauscht werden.
Wenn ein Browser eine Cross-Origin-Anfrage stellt (d. h. eine Anfrage an eine andere Herkunft als die aktuelle Seite), prüft er zunächst, ob der Server die Anfrage zulässt. Dies geschieht durch die Untersuchung des Access-Control-Allow-Origin-Headers in der Antwort des Servers. Wenn die Herkunft der Anfrage in diesem Header aufgeführt ist (oder wenn der Header auf * gesetzt ist, was alle Herkünfte erlaubt), lässt der Browser die Anfrage zu. Andernfalls blockiert der Browser die Anfrage und verhindert, dass der JavaScript-Code auf die Antwortdaten zugreift.
Die Rolle von Preflight-Anfragen
Für bestimmte Arten von Cross-Origin-Anfragen initiiert der Browser eine Preflight-Anfrage. Dies ist eine OPTIONS-Anfrage, die vor der eigentlichen Anfrage an den Server gesendet wird. Der Zweck der Preflight-Anfrage besteht darin, festzustellen, ob der Server bereit ist, die eigentliche Anfrage zu akzeptieren. Der Server antwortet auf die Preflight-Anfrage mit Informationen über die erlaubten Methoden, Header und andere Einschränkungen.
Preflight-Anfragen werden ausgelöst, wenn die Cross-Origin-Anfrage eine der folgenden Bedingungen erfüllt:
- Die Anfragemethode ist nicht
GET,HEADoderPOST. - Die Anfrage enthält benutzerdefinierte Header (d. h. andere Header als die, die vom Browser automatisch hinzugefügt werden).
- Der
Content-Type-Header ist auf etwas anderes alsapplication/x-www-form-urlencoded,multipart/form-dataodertext/plaingesetzt. - Die Anfrage verwendet
ReadableStream-Objekte im Body.
Zum Beispiel wird eine PUT-Anfrage mit einem Content-Type von application/json eine Preflight-Anfrage auslösen, da sie eine andere Methode als die erlaubten und einen potenziell nicht erlaubten Inhaltstyp verwendet.
Warum Preflight-Anfragen?
Preflight-Anfragen sind für die Sicherheit unerlässlich, da sie dem Server die Möglichkeit geben, potenziell schädliche Cross-Origin-Anfragen abzulehnen, bevor sie ausgeführt werden. Ohne Preflight-Anfragen könnte eine bösartige Website potenziell beliebige Anfragen an einen Server senden, ohne dessen ausdrückliche Zustimmung. Eine Preflight-Anfrage ermöglicht es dem Server, zu überprüfen, ob die Anfrage akzeptabel ist, und verhindert potenziell schädliche Operationen.
Handhabung von Preflight-Anfragen auf der Serverseite
Die ordnungsgemäße Handhabung von Preflight-Anfragen ist entscheidend, um sicherzustellen, dass Ihre Webanwendung korrekt und sicher funktioniert. Der Server muss auf die OPTIONS-Anfrage mit den entsprechenden CORS-Headern antworten, um anzuzeigen, ob die eigentliche Anfrage erlaubt ist.
Hier ist eine Aufschlüsselung der wichtigsten CORS-Header, die in Preflight-Antworten verwendet werden:
Access-Control-Allow-Origin: Dieser Header gibt die Herkunft(en) an, die auf die Ressource zugreifen dürfen. Er kann auf eine bestimmte Herkunft (z. B.https://www.example.com) oder auf*gesetzt werden, um alle Herkünfte zu erlauben. Die Verwendung von*wird jedoch aus Sicherheitsgründen generell nicht empfohlen, insbesondere wenn der Server sensible Daten verarbeitet.Access-Control-Allow-Methods: Dieser Header gibt die HTTP-Methoden an, die für die Cross-Origin-Anfrage erlaubt sind (z. B.GET,POST,PUT,DELETE).Access-Control-Allow-Headers: Dieser Header gibt die Liste der nicht-standardmäßigen HTTP-Header an, die in der eigentlichen Anfrage erlaubt sind. Dies ist notwendig, wenn der Client benutzerdefinierte Header wieX-Custom-HeaderoderAuthorizationsendet.Access-Control-Allow-Credentials: Dieser Header gibt an, ob die eigentliche Anfrage Anmeldeinformationen wie Cookies oder Autorisierungs-Header enthalten darf. Er muss auftruegesetzt werden, wenn der clientseitige Code Anmeldeinformationen sendet und der Server diese akzeptieren soll. Hinweis: Wenn dieser Header auf `true` gesetzt ist, darf `Access-Control-Allow-Origin` *nicht* auf `*` gesetzt werden. Sie müssen die Herkunft angeben.Access-Control-Max-Age: Dieser Header gibt die maximale Zeit (in Sekunden) an, für die der Browser die Preflight-Antwort zwischenspeichern kann. Dies kann die Leistung verbessern, indem die Anzahl der gesendeten Preflight-Anfragen reduziert wird.
Beispiel: Handhabung von Preflight-Anfragen in Node.js mit Express
Hier ist ein Beispiel, wie man Preflight-Anfragen in einer Node.js-Anwendung mit dem Express-Framework handhabt:
const express = require('express');
const cors = require('cors');
const app = express();
// Enable CORS for all origins (for development purposes only!)
// In production, specify allowed origins for better security.
app.use(cors()); //or app.use(cors({origin: 'https://www.example.com'}));
// Route for handling OPTIONS requests (preflight)
app.options('/data', cors()); // Enable CORS for a single route. Or specify origin: cors({origin: 'https://www.example.com'})
// Route for handling GET requests
app.get('/data', (req, res) => {
res.json({ message: 'This is cross-origin data!' });
});
// Route to handle a preflight and a post request
app.options('/resource', cors()); // enable pre-flight request for DELETE request
app.delete('/resource', cors(), (req, res, next) => {
res.send('delete resource')
})
const port = 3000;
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
In diesem Beispiel verwenden wir die cors-Middleware, um CORS-Anfragen zu behandeln. Für eine granularere Steuerung kann CORS pro Route aktiviert werden. Hinweis: In der Produktion wird dringend empfohlen, die erlaubten Herkünfte mit der origin-Option anzugeben, anstatt alle Herkünfte zu erlauben. Das Zulassen aller Herkünfte mit * kann Ihre Anwendung Sicherheitslücken aussetzen.
Beispiel: Handhabung von Preflight-Anfragen in Python mit Flask
Hier ist ein Beispiel, wie man Preflight-Anfragen in einer Python-Anwendung mit dem Flask-Framework und der flask_cors-Erweiterung handhabt:
from flask import Flask, jsonify
from flask_cors import CORS, cross_origin
app = Flask(__name__)
CORS(app) # Enable CORS for all routes
@app.route('/data')
@cross_origin()
def get_data():
data = {"message": "This is cross-origin data!"}
return jsonify(data)
if __name__ == '__main__':
app.run(debug=True)
Dies ist die einfachste Verwendung. Wie zuvor können die Herkünfte eingeschränkt werden. Details finden Sie in der flask-cors-Dokumentation.
Beispiel: Handhabung von Preflight-Anfragen in Java mit Spring Boot
Hier ist ein Beispiel, wie man Preflight-Anfragen in einer Java-Anwendung mit Spring Boot handhabt:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@SpringBootApplication
public class CorsApplication {
public static void main(String[] args) {
SpringApplication.run(CorsApplication.class, args);
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/data").allowedOrigins("http://localhost:8080");
}
};
}
}
Und der entsprechende Controller:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DataController {
@GetMapping("/data")
public String getData() {
return "This is cross-origin data!";
}
}
Häufige CORS-Probleme und Lösungen
Trotz seiner Bedeutung kann CORS für Entwickler oft eine Quelle der Frustration sein. Hier sind einige häufige CORS-Probleme und ihre Lösungen:
-
Fehler: "No 'Access-Control-Allow-Origin' header is present on the requested resource."
Dieser Fehler zeigt an, dass der Server den
Access-Control-Allow-Origin-Header in seiner Antwort nicht zurückgibt. Um dies zu beheben, stellen Sie sicher, dass der Server so konfiguriert ist, dass er den Header enthält und dass er auf die korrekte Herkunft oder auf*(falls zutreffend) gesetzt ist.Lösung: Konfigurieren Sie den Server so, dass er den `Access-Control-Allow-Origin`-Header in seiner Antwort enthält und ihn auf die Herkunft der anfragenden Website oder auf `*` setzt, um alle Herkünfte zu erlauben (mit Vorsicht verwenden).
-
Fehler: "Response to preflight request doesn't pass access control check: Request header field X-Custom-Header is not allowed by Access-Control-Allow-Headers in preflight response."
Dieser Fehler zeigt an, dass der Server den benutzerdefinierten Header (
X-Custom-Headerin diesem Beispiel) in der Cross-Origin-Anfrage nicht zulässt. Um dies zu beheben, stellen Sie sicher, dass der Server den Header in denAccess-Control-Allow-Headers-Header in der Preflight-Antwort aufnimmt.Lösung: Fügen Sie den benutzerdefinierten Header (z. B. `X-Custom-Header`) zum `Access-Control-Allow-Headers`-Header in der Preflight-Antwort des Servers hinzu.
-
Fehler: "Credentials flag is 'true', but the 'Access-Control-Allow-Origin' header is '*'."
Wenn der
Access-Control-Allow-Credentials-Header auftruegesetzt ist, muss derAccess-Control-Allow-Origin-Header auf eine bestimmte Herkunft und nicht auf*gesetzt werden. Dies liegt daran, dass das Zulassen von Anmeldeinformationen von allen Herkünften ein Sicherheitsrisiko wäre.Lösung: Wenn Sie Anmeldeinformationen verwenden, setzen Sie `Access-Control-Allow-Origin` auf eine bestimmte Herkunft anstelle von `*`.
-
Preflight-Anfrage wird nicht gesendet.
Überprüfen Sie, ob Ihr Javascript-Code die Eigenschaft `credentials: 'include'` enthält. Überprüfen Sie auch, ob Ihr Server `Access-Control-Allow-Credentials: true` erlaubt.
-
Widersprüchliche Konfigurationen zwischen Server und Client.
Überprüfen Sie sorgfältig Ihre serverseitige CORS-Konfiguration zusammen mit den clientseitigen Einstellungen. Nichtübereinstimmungen (z. B. wenn der Server nur GET-Anfragen erlaubt, der Client aber POST sendet) verursachen CORS-Fehler.
CORS und bewährte Sicherheitspraktiken
Obwohl CORS einen kontrollierten Cross-Origin-Zugriff ermöglicht, ist es unerlässlich, bewährte Sicherheitspraktiken zu befolgen, um Schwachstellen zu vermeiden:
- Vermeiden Sie die Verwendung von
*imAccess-Control-Allow-Origin-Header in der Produktion. Dies erlaubt allen Herkünften den Zugriff auf Ihre Ressourcen, was ein Sicherheitsrisiko darstellen kann. Geben Sie stattdessen die genauen Herkünfte an, die erlaubt sind. - Überlegen Sie sorgfältig, welche Methoden und Header Sie zulassen. Erlauben Sie nur die Methoden und Header, die für das korrekte Funktionieren Ihrer Anwendung unbedingt erforderlich sind.
- Implementieren Sie ordnungsgemäße Authentifizierungs- und Autorisierungsmechanismen. CORS ist kein Ersatz für Authentifizierung und Autorisierung. Stellen Sie sicher, dass Ihre API durch geeignete Sicherheitsmaßnahmen geschützt ist.
- Validieren und bereinigen Sie alle Benutzereingaben. Dies hilft, Cross-Site-Scripting (XSS)-Angriffe und andere Schwachstellen zu verhindern.
- Halten Sie Ihre serverseitige CORS-Konfiguration auf dem neuesten Stand. Überprüfen und aktualisieren Sie Ihre CORS-Konfiguration regelmäßig, um sicherzustellen, dass sie den Sicherheitsanforderungen Ihrer Anwendung entspricht.
CORS in verschiedenen Entwicklungsumgebungen
CORS-Probleme können sich in verschiedenen Entwicklungsumgebungen und Technologien unterschiedlich manifestieren. Hier ist ein Blick darauf, wie man CORS in einigen gängigen Szenarien angeht:
Lokale Entwicklungsumgebungen
Während der lokalen Entwicklung können CORS-Probleme besonders ärgerlich sein. Browser blockieren oft Anfragen von Ihrem lokalen Entwicklungsserver (z. B. localhost:3000) an eine Remote-API. Mehrere Techniken können diesen Schmerz lindern:
- Browser-Erweiterungen: Erweiterungen wie "Allow CORS: Access-Control-Allow-Origin" können CORS-Einschränkungen zu Testzwecken vorübergehend deaktivieren. Verwenden Sie diese jedoch *niemals* in der Produktion.
- Proxy-Server: Konfigurieren Sie einen Proxy-Server, der Anfragen von Ihrem lokalen Entwicklungsserver an die Remote-API weiterleitet. Dies macht die Anfragen aus Sicht des Browsers effektiv zu "Same-Origin"-Anfragen. Tools wie
http-proxy-middleware(für Node.js) sind hierfür hilfreich. - Server-CORS konfigurieren: Auch während der Entwicklung ist es eine bewährte Praxis, Ihren API-Server so zu konfigurieren, dass er Anfragen von Ihrer lokalen Entwicklungsherkunft (z. B.
http://localhost:3000) explizit zulässt. Dies simuliert eine reale CORS-Konfiguration und hilft Ihnen, Probleme frühzeitig zu erkennen.
Serverless-Umgebungen (z. B. AWS Lambda, Google Cloud Functions)
Serverless-Funktionen erfordern oft eine sorgfältige CORS-Konfiguration. Viele Serverless-Plattformen bieten integrierte CORS-Unterstützung, aber es ist entscheidend, sie korrekt zu konfigurieren:
- Plattformspezifische Einstellungen: Nutzen Sie die integrierten CORS-Konfigurationsoptionen der Plattform. AWS Lambda ermöglicht es Ihnen beispielsweise, erlaubte Herkünfte, Methoden und Header direkt in den API-Gateway-Einstellungen anzugeben.
- Middleware/Bibliotheken: Für mehr Flexibilität können Sie Middleware oder Bibliotheken verwenden, um CORS innerhalb Ihres Serverless-Funktionscodes zu handhaben. Dies ähnelt den Ansätzen in traditionellen Serverumgebungen (z. B. die Verwendung des `cors`-Pakets in Node.js-Lambda-Funktionen).
- Berücksichtigen Sie die
OPTIONS-Methode: Stellen Sie sicher, dass Ihre Serverless-FunktionOPTIONS-Anfragen korrekt behandelt. Dies erfordert oft die Erstellung einer separaten Route, die die entsprechenden CORS-Header zurückgibt.
Mobile App-Entwicklung (z. B. React Native, Flutter)
CORS ist für native mobile Apps (Android, iOS) weniger ein direktes Anliegen, da sie die Same-Origin-Policy normalerweise nicht auf die gleiche Weise wie Webbrowser durchsetzen. CORS kann jedoch immer noch relevant sein, wenn Ihre mobile App eine Webansicht verwendet, um Webinhalte anzuzeigen, oder wenn Sie Frameworks wie React Native oder Flutter verwenden, die JavaScript nutzen:
- Webansichten: Wenn Ihre mobile App eine Webansicht verwendet, um Webinhalte anzuzeigen, gelten die gleichen CORS-Regeln wie in einem Webbrowser. Konfigurieren Sie Ihren Server so, dass er Anfragen von der Herkunft des Webinhalts zulässt.
- React Native/Flutter: Diese Frameworks verwenden JavaScript, um API-Anfragen zu stellen. Obwohl die native Umgebung CORS möglicherweise nicht direkt durchsetzt, können die zugrunde liegenden HTTP-Clients (z. B.
fetch) in bestimmten Situationen immer noch ein CORS-ähnliches Verhalten zeigen. - Native HTTP-Clients: Wenn API-Anfragen direkt aus dem nativen Code gestellt werden (z. B. mit OkHttp auf Android oder URLSession auf iOS), ist CORS im Allgemeinen kein Faktor. Sie müssen jedoch weiterhin bewährte Sicherheitspraktiken wie eine ordnungsgemäße Authentifizierung und Autorisierung berücksichtigen.
Globale Überlegungen zur CORS-Konfiguration
Bei der Konfiguration von CORS für eine global zugängliche Anwendung ist es entscheidend, Faktoren wie die folgenden zu berücksichtigen:
- Datensouveränität: Vorschriften in einigen Regionen schreiben vor, dass Daten innerhalb der Region verbleiben müssen. CORS kann beim Zugriff auf Ressourcen über Grenzen hinweg eine Rolle spielen und potenziell gegen Gesetze zur Datenresidenz verstoßen.
- Regionale Sicherheitsrichtlinien: Verschiedene Länder können unterschiedliche Cybersicherheitsvorschriften und -richtlinien haben, die beeinflussen, wie CORS implementiert und gesichert werden sollte.
- Content Delivery Networks (CDNs): Stellen Sie sicher, dass Ihr CDN ordnungsgemäß konfiguriert ist, um die erforderlichen CORS-Header durchzulassen. Falsch konfigurierte CDNs können CORS-Header entfernen, was zu unerwarteten Fehlern führt.
- Load Balancer und Proxies: Überprüfen Sie, ob alle Load Balancer oder Reverse Proxies in Ihrer Infrastruktur Preflight-Anfragen korrekt behandeln und CORS-Header durchlassen.
- Mehrsprachige Unterstützung: Bedenken Sie, wie CORS mit den Internationalisierungs- (i18n) und Lokalisierungsstrategien (l10n) Ihrer Anwendung interagiert. Stellen Sie sicher, dass die CORS-Richtlinien über verschiedene Sprachversionen Ihrer Anwendung hinweg konsistent sind.
Testen und Debuggen von CORS
Effektives Testen und Debuggen von CORS ist unerlässlich. Hier sind einige Techniken:
- Browser-Entwicklertools: Die Entwicklerkonsole des Browsers ist Ihre erste Anlaufstelle. Der „Netzwerk“-Tab zeigt Preflight-Anfragen und die Antworten an und deckt auf, ob CORS-Header vorhanden und korrekt konfiguriert sind.
- `curl` Kommandozeilen-Tool: Verwenden Sie `curl -v -X OPTIONS
`, um Preflight-Anfragen manuell zu senden und die Antwort-Header des Servers zu inspizieren. - Online-CORS-Checker: Zahlreiche Online-Tools können helfen, Ihre CORS-Konfiguration zu validieren. Suchen Sie einfach nach „CORS Checker“.
- Unit- und Integrationstests: Schreiben Sie automatisierte Tests, um zu überprüfen, ob Ihre CORS-Konfiguration wie erwartet funktioniert. Diese Tests sollten sowohl erfolgreiche Cross-Origin-Anfragen als auch Szenarien abdecken, in denen CORS den Zugriff blockieren sollte.
- Protokollierung und Überwachung: Implementieren Sie eine Protokollierung, um CORS-bezogene Ereignisse wie Preflight-Anfragen und blockierte Anfragen zu verfolgen. Überwachen Sie Ihre Protokolle auf verdächtige Aktivitäten oder Konfigurationsfehler.
Fazit
Cross-Origin Resource Sharing (CORS) ist ein wesentlicher Sicherheitsmechanismus, der einen kontrollierten Cross-Origin-Zugriff auf Webressourcen ermöglicht. Das Verständnis, wie CORS funktioniert, insbesondere Preflight-Anfragen, ist entscheidend für die Erstellung sicherer und zuverlässiger Webanwendungen. Indem Sie die in diesem Leitfaden beschriebenen bewährten Praktiken befolgen, können Sie CORS-Probleme effektiv behandeln und Ihre Anwendung vor potenziellen Schwachstellen schützen. Denken Sie daran, der Sicherheit immer Vorrang zu geben und die Auswirkungen Ihrer CORS-Konfiguration sorgfältig zu bedenken.
Während sich die Webentwicklung weiterentwickelt, wird CORS weiterhin ein kritischer Aspekt der Websicherheit sein. Sich über die neuesten CORS-Best Practices und Techniken auf dem Laufenden zu halten, ist für die Erstellung sicherer und global zugänglicher Webanwendungen unerlässlich.